import __builtin__
import cPickle as pickle
import blue
import miscUtil
import log
import locale
import localization
import localizationUtil
import util
import re
import uthread
import os
import xml.etree.ElementTree
logChannel = log.GetChannel('Localization')

def LogInfo(*args):
    logChannel.Log(('Localization module: ' + ''.join(map(strx, args))), logChannel.flags['INFO'])



def LogWarn(*args):
    logChannel.Log(('Localization module: ' + ''.join(map(strx, args))), logChannel.flags['WARN'])



def LogError(*args):
    logChannel.Log(('Localization module: ' + ''.join(map(strx, args))), logChannel.flags['ERR'])



class Localization(object):
    __guid__ = 'localization.Localization'
    PICKLE_PREFIX = 'localization_'
    PICKLE_MAIN_NAME = 'localization_main'
    PICKLE_EXT = '.pickle'
    COMMON_FILE_PATH = (blue.os.rootpath + '../common/res/localization/')
    COMMON_RESOURCE_PATH = 'res:/localization/'
    COLUMN_TEXT = 'text'
    COLUMN_MESSAGEID = 'messageID'
    COLUMN_LABEL = 'label'
    COLUMN_FULLPATH = 'FullPath'
    COLUMN_LANGUAGEID = 'languageID'
    COLUMN_PROPERTY_NAME = 'propertyName'
    COLUMN_METADATA_VALUE = 'metaDataValue'
    COLUMN_LANGUAGE_CODE_STRING = 'languageCodeString'
    COLUMN_TYPE_NAME = 'typeName'
    COLUMN_SCHEMA_REG_NAME = 'schemaRegName'
    COLUMN_TABLE_REG_NAME = 'tableRegName'
    COLUMN_COLUMN_REG_NAME = 'columnRegName'
    COLUMN_TABLE_REG_ID = 'tableRegID'
    COLUMN_KEY_ID = 'keyID'
    FIELD_LABELS = 'labels'
    FIELD_LANGUAGES = 'languages'
    FIELD_MAPPING = 'mapping'
    FIELD_REGISTRATION = 'registration'
    FIELD_TYPES = 'types'
    LANGUAGE_FIELD_CODE = 0
    LANGUAGE_FIELD_TEXTS = 1
    LANGUAGE_FIELD_DATA = 2
    LANGUAGE_NUMBER_OF_FIELDS = 3
    IDENTIFIER_TYPE_NAMES = ['characters',
     'characterLists',
     'items',
     'locations',
     'dateTimes',
     'dateTimeQuantities',
     'numericQuantities',
     'undefined']
    IS_INVALID_TYPE = 0
    IS_INVALID_PROPERTY = 1
    IS_VALID_TYPE_AND_PROPERTY = 2
    MAX_GROUP_DEPTH = 100

    def __init__(self):
        self._ReadLocalizationPickle()
        uthread.worker('localization::_SetHardcodedStringDetection', self._SetHardcodedStringDetection)
        self.ChangeLocale()
        print 'Cerberus localization module loaded on',
        print boot.role



    def ChangeLocale(self, localeName = ''):
        if (localeName != locale.getlocale()[0]):
            locale.setlocale(locale.LC_ALL, localeName)



    def GetResourceFilePaths(self):
        filenameList = []
        mainPicklePath = os.path.abspath(((self.COMMON_FILE_PATH + self.PICKLE_MAIN_NAME) + self.PICKLE_EXT))
        filenameList.append(mainPicklePath)
        db2service = sm.GetService('DB2')
        for row in db2service.zlocalization.LanguageCodes_SelectEnabled():
            languagePicklePath = os.path.abspath((((self.COMMON_FILE_PATH + self.PICKLE_PREFIX) + row.languageCodeString) + self.PICKLE_EXT))
            filenameList.append(languagePicklePath)

        return filenameList



    def ImportFromXMLFileIntoDatabase(self, fileName):
        if not fileName:
            return 
        else:
            textDataTree = xml.etree.ElementTree.ElementTree()
            textDataTree.parse(fileName)
            return self._ImportXMLIntoDatabase(textRootElement=textDataTree)



    def ImportXMLIntoDatabase(self, translatedTextXML = None):
        if translatedTextXML:
            textRootElement = xml.etree.ElementTree.fromstringlist(translatedTextXML.encode('utf-8'))
        return self._ImportXMLIntoDatabase(textRootElement=textRootElement)



    def ExportToXMLFileFromDatabase(self, fileName):
        if not fileName:
            return 
        else:
            textsElement = self._ExportXMLElementsFromDatabase()
            textsElementTree = xml.etree.ElementTree.ElementTree(textsElement)
            textsElementTree.write(fileName, encoding='utf-8')
            return True



    def ExportXMLFromDatabase(self):
        textsElement = self._ExportXMLElementsFromDatabase()
        textsXMLString = xml.etree.ElementTree.tostring(textsElement, encoding='utf-8').decode('utf-8')
        return textsXMLString



    def WriteLocalizationPickle(self, getSubmittedOnly = False):
        exportedFilenames = []
        db2service = sm.GetService('DB2')
        if not db2service:
            LogError(('didnt get the DB2 service. db2service = %s' % db2service))
            return exportedFilenames
        else:
            languageIDToCode = {}
            messagePerLanguage = {}
            metaDataPerLanguage = {}
            languageCodesResultSet = db2service.zlocalization.LanguageCodes_SelectEnabled()
            languageCodesDict = self._MakeRowDicts(languageCodesResultSet, languageCodesResultSet.columns, self.COLUMN_LANGUAGE_CODE_STRING)
            getTableDataForPicklingResultSet = db2service.zlocalization.GetTableDataForPickling((1 if getSubmittedOnly else 0))
            messageResultSet = getTableDataForPicklingResultSet[0]
            wordMetaResultSet = getTableDataForPicklingResultSet[1]
            registrationResultSet = getTableDataForPicklingResultSet[2]
            mappingResultSet = getTableDataForPicklingResultSet[3]
            labelsResultSet = getTableDataForPicklingResultSet[4]
            typesWithPropertiesSet = getTableDataForPicklingResultSet[5]
            messageTextsDict = self._MakeRowDicts(rowList=messageResultSet, columnNames=[self.COLUMN_MESSAGEID,
             self.COLUMN_LANGUAGEID,
             self.COLUMN_TEXT])
            wordMetaDataDict = self._MakeRowDicts(rowList=wordMetaResultSet, columnNames=wordMetaResultSet.columns)
            registrationDict = self._MakeRowDicts(rowList=registrationResultSet, columnNames=registrationResultSet.columns)
            mappingDict = self._MakeRowDicts(rowList=mappingResultSet, columnNames=mappingResultSet.columns)
            labelsDict = self._MakeRowDicts(rowList=labelsResultSet, columnNames=labelsResultSet.columns, tableUniqueKey=self.COLUMN_MESSAGEID)
            typesWithPropertiesDict = self._MakeRowDicts(rowList=typesWithPropertiesSet, columnNames=typesWithPropertiesSet.columns)
            for languageCodeRow in languageCodesResultSet:
                languageCodeString = getattr(languageCodeRow, self.COLUMN_LANGUAGE_CODE_STRING)
                languageID = getattr(languageCodeRow, self.COLUMN_LANGUAGEID)
                languageIDToCode[languageID] = languageCodeString
                messagePerLanguage[languageCodeString] = {}
                metaDataPerLanguage[languageCodeString] = {}

            registrationData = {}
            for aRowKey in registrationDict:
                aRow = registrationDict[aRowKey]
                registrationData[((((aRow[self.COLUMN_SCHEMA_REG_NAME] + '.') + aRow[self.COLUMN_TABLE_REG_NAME]) + '.') + aRow[self.COLUMN_COLUMN_REG_NAME])] = aRow[self.COLUMN_TABLE_REG_ID]

            mappingData = {}
            for aRowKey in mappingDict:
                aRow = mappingDict[aRowKey]
                mappingData[(aRow[self.COLUMN_TABLE_REG_ID], aRow[self.COLUMN_KEY_ID])] = aRow[self.COLUMN_MESSAGEID]

            typesWithPropertiesData = {}
            for aRowKey in typesWithPropertiesDict:
                aRow = typesWithPropertiesDict[aRowKey]
                languageToProperties = typesWithPropertiesData.get(aRow[self.COLUMN_TYPE_NAME], None)
                if (languageToProperties is None):
                    languageToProperties = {}
                    typesWithPropertiesData[aRow[self.COLUMN_TYPE_NAME]] = languageToProperties
                propertyList = languageToProperties.get(aRow[self.COLUMN_LANGUAGE_CODE_STRING], None)
                if ((propertyList is None) and (aRow[self.COLUMN_PROPERTY_NAME] is not None)):
                    propertyList = []
                    languageToProperties[aRow[self.COLUMN_LANGUAGE_CODE_STRING]] = propertyList
                if (propertyList is not None):
                    propertyList.append(aRow[self.COLUMN_PROPERTY_NAME])

            filename = ((self.COMMON_FILE_PATH + self.PICKLE_MAIN_NAME) + self.PICKLE_EXT)
            with open(filename, 'wb') as pickleFile:
                dataToPickle = {}
                dataToPickle[self.FIELD_LABELS] = labelsDict
                dataToPickle[self.FIELD_LANGUAGES] = languageCodesDict
                dataToPickle[self.FIELD_REGISTRATION] = registrationData
                dataToPickle[self.FIELD_MAPPING] = mappingData
                dataToPickle[self.FIELD_TYPES] = typesWithPropertiesData
                pickle.dump(dataToPickle, pickleFile)
            exportedFilenames.append(filename)
            pickleFile = None
            for aMessageKeyEntry in messageTextsDict:
                messageLanguageID = messageTextsDict[aMessageKeyEntry][self.COLUMN_LANGUAGEID]
                aMessageID = messageTextsDict[aMessageKeyEntry][self.COLUMN_MESSAGEID]
                aLanguageCode = languageIDToCode[messageLanguageID]
                messagePerLanguage[aLanguageCode][aMessageID] = messageTextsDict[aMessageKeyEntry][self.COLUMN_TEXT]

            for aMetaEntryKey in wordMetaDataDict:
                metaLanguageID = wordMetaDataDict[aMetaEntryKey][self.COLUMN_LANGUAGEID]
                aPropertyName = wordMetaDataDict[aMetaEntryKey][self.COLUMN_PROPERTY_NAME]
                languageMetaEntry = metaDataPerLanguage[languageIDToCode[metaLanguageID]]
                aMessageID = wordMetaDataDict[aMetaEntryKey][self.COLUMN_MESSAGEID]
                if ((aMessageID not in languageMetaEntry) or (languageMetaEntry[aMessageID] is None)):
                    languageMetaEntry[aMessageID] = {}
                languageMetaEntry[aMessageID][aPropertyName] = wordMetaDataDict[aMetaEntryKey][self.COLUMN_METADATA_VALUE]

            for aLanguageCode in messagePerLanguage:
                filename = (((self.COMMON_FILE_PATH + self.PICKLE_PREFIX) + aLanguageCode) + self.PICKLE_EXT)
                with open(filename, 'wb') as pickleFile:
                    dataToPickle = (aLanguageCode,
                     messagePerLanguage[aLanguageCode],
                     metaDataPerLanguage[aLanguageCode])
                    pickle.dump(dataToPickle, pickleFile)
                pickleFile = None
                exportedFilenames.append(filename)

            return exportedFilenames



    def GetByMapping(self, resourceName, keyID, propertyName = None, languageID = None, **kwargs):
        try:
            tableRegID = self.tableRegistration[resourceName]
            messageID = self.messageMapping[(tableRegID, keyID)]
            if (propertyName is None):
                return self.GetByID(messageID, languageID, **kwargs)
            else:
                return self.GetMetaData(messageID, propertyName, languageID)
        except KeyError, e:
            LogError(("mapping wasn't found for resourceName,keyID,propertyName,languageID : '%s',%s,%s,%s" % (resourceName,
             keyID,
             propertyName,
             languageID)))
            return ('[no data:%s,%s]' % (resourceName, keyID))



    def GetByID(self, messageID, languageID = None, **kwargs):
        languageID = (languageID or self._GetLanguageFromSession())
        textString = None
        if (languageID == localization.ISO_PSEUDOLOC_DEFAULT):
            textString = self._GetByID(messageID, localization.ISO_CODE_ENGLISH, **kwargs)
            if (textString is not None):
                textString = localization.Pseudolocalize(textString, messageID=messageID)
        else:
            textString = self._GetByID(messageID, languageID, **kwargs)
        if (textString is not None):
            return localizationUtil.LocalizationSafeString(textString)
        else:
            return ('[no message:%s]' % messageID)



    def GetByLabel(self, labelNameAndPath, languageID = None, **kwargs):
        try:
            messageID = self.languageLabels[labelNameAndPath][self.COLUMN_MESSAGEID]
        except KeyError, e:
            LogError(('A non-existent label was requested. Label: %s, %s' % (labelNameAndPath, languageID)))
            return ('[no label:%s]' % labelNameAndPath)
        return self.GetByID(messageID, languageID, **kwargs)



    def IsValidTypeAndProperty(self, typeName, propertyName, languageID = None):
        returnValue = None
        if (languageID is None):
            languageID = self._GetLanguageFromSession()
        if (languageID == localization.ISO_PSEUDOLOC_DEFAULT):
            languageID = localization.ISO_CODE_ENGLISH
        foundType = self.languageTypesWithProperties.get(typeName, None)
        if (foundType is not None):
            foundPropertyList = foundType.get(languageID, None)
            if (foundPropertyList is not None):
                if (propertyName in foundPropertyList):
                    returnValue = self.IS_VALID_TYPE_AND_PROPERTY
                else:
                    returnValue = self.IS_INVALID_PROPERTY
            else:
                returnValue = self.IS_INVALID_PROPERTY
        else:
            returnValue = self.IS_INVALID_TYPE
        if (returnValue is None):
            returnValue = self.IS_INVALID_TYPE
            LogError(('IsValidTypeAndProperty wasnt able to determine if type and property were valid: %s,%s' % (typeName, propertyName)))
        return returnValue



    def GetMetaData(self, messageID, propertyName, languageID = None):
        propertyString = None
        if (languageID is None):
            languageID = self._GetLanguageFromSession()
        if (languageID == localization.ISO_PSEUDOLOC_DEFAULT):
            englishString = self._GetMetaData(messageID, propertyName, localization.ISO_CODE_ENGLISH)
            if (englishString is not None):
                propertyString = localization.Pseudolocalize(englishString, messageID=messageID)
        else:
            propertyString = self._GetMetaData(messageID, propertyName, languageID)
        if (propertyString is not None):
            return localizationUtil.LocalizationSafeString(propertyString)
        else:
            LogError(('a non existent property was requested. messageID,propertyName,languageID : %s,%s,%s' % (messageID,
             propertyName,
             languageID)))
            return ('[no property:%s,%s]' % (messageID, propertyName))



    def GetAllMetaData(self, messageID):
        propertiesDict = None
        if (len(self.languageMetaData) > 0):
            propertiesDict = {}
            for aLanguageID in self.languageMetaData:
                propertiesDict[aLanguageID] = self._GetAllMetaDataPerLanguage(messageID, aLanguageID)

        return propertiesDict



    def GetAllMetaDataPerLanguage(self, messageID, languageID = None):
        if (languageID is None):
            languageID = self._GetLanguageFromSession()
        return self._GetAllMetaDataPerLanguage(messageID, languageID)



    def GetPlaceholderLabel(self, englishText, **kwargs):
        parsedText = localization._Parse(englishText, None, localization.ISO_CODE_ENGLISH, **kwargs)
        LogWarn(('Placeholder label (%s) needs to be replaced.' % englishText))
        if (self._GetLanguageFromSession() == localization.ISO_PSEUDOLOC_DEFAULT):
            parsedText = localization.Pseudolocalize(parsedText)
        return localizationUtil.LocalizationSafeString(('!_%s_!' % parsedText))



    def SyncDataFromRegisteredTables(self):
        bsdTableService = sm.GetService('bsdTable')
        regTable = bsdTableService.GetTable(localization.EXTERNAL_REGISTRATION_TABLE)
        groupTable = bsdTableService.GetTable(localization.MESSAGE_GROUPS_TABLE)
        messagesTable = bsdTableService.GetTable(localization.MESSAGES_TABLE)
        allRegistered = regTable.GetRows()
        updatedEntriesPerTable = {}
        for aRow in allRegistered:
            tableRegID = aRow.tableRegID
            textColumnName = aRow.columnRegName
            uniqueIDName = aRow.uniqueIDName
            groupPathName = aRow.groupPathName
            groupID = aRow.groupID
            groupRow = groupTable.GetRowByKey(keyId1=groupID)
            wordTypeID = groupRow.wordTypeID
            groupRow.isReadOnly = 1
            registeredTypeID = aRow.registeredTypeID
            tableSchema = aRow.schemaRegName
            tableName = aRow.tableRegName
            label = ((((tableSchema + '.') + tableName) + '.') + textColumnName)
            syncResult = {}
            syncResult[localization.KeyToMessageMapping.UNCHANGED_ENTRY] = 0
            syncResult[localization.KeyToMessageMapping.ADDED_ENTRY] = 0
            syncResult[localization.KeyToMessageMapping.UPDATED_ENTRY] = 0
            syncResult[localization.KeyToMessageMapping.DELETED_ENTRY] = 0
            updatedEntriesPerTable['.'.join((aRow.schemaRegName,
             aRow.tableRegName,
             aRow.columnRegName))] = syncResult
            allTableData = None
            if (registeredTypeID == localization.REGISTERED_TYPE_DYNAMIC):
                db2service = sm.GetService('DB2')
                try:
                    allTableData = db2service.zlocalization.RegisteredResources_SelectOnRegisteredResource(tableRegID)
                except SQLError:
                    LogError(("failed when attempting to read a table/view resource : tableRegID = '%s'" % tableRegID))
            elif (registeredTypeID == localization.REGISTERED_TYPE_BSD):
                try:
                    registeredTable = bsdTableService.GetTable(((tableSchema + '.') + tableName))
                    allTableData = registeredTable.GetRows()
                except RuntimeError:
                    LogError(("failed when attempting to read a BSD table : '%s'" % ((tableSchema + '.') + tableName)))
            else:
                LogError(("encountered unknown registered resource type : '%s' of type '%s'" % (((tableSchema + '.') + tableName), registeredTypeID)))
            if (allTableData is not None):
                cachedGroupPaths = {}
                possibleOrphanedGroups = set()
                updatedMappedEntries = []
                for aTableRow in allTableData:
                    englishText = getattr(aTableRow, textColumnName, None)
                    keyIDValue = getattr(aTableRow, uniqueIDName, None)
                    if ((registeredTypeID == localization.REGISTERED_TYPE_DYNAMIC) and (groupPathName is not None)):
                        groupPathString = getattr(aTableRow, groupPathName, None)
                        if ((groupPathString is not None) and (groupPathString != '')):
                            if (groupPathString in cachedGroupPaths):
                                groupID = cachedGroupPaths[groupPathString]
                            else:
                                (groupID, isNewGroup,) = self._ResolveDynamicPath(groupPathString, aRow.groupID, wordTypeID)
                                cachedGroupPaths[groupPathString] = groupID
                                if (isNewGroup == True):
                                    mappingEntry = localization.KeyToMessageMapping.GetMapping(keyIDValue, tableRegID)
                                    if (mappingEntry is not None):
                                        messageEntry = localization.Message.GetMessageByID(mappingEntry.messageID)
                                        if (messageEntry is not None):
                                            possibleOrphanedGroups.add(messageEntry.groupID)
                        else:
                            groupID = aRow.groupID
                    updatedMappedEntries.append(keyIDValue)
                    mappingResult = localization.KeyToMessageMapping.AddOrUpdateEntry(keyIDValue=keyIDValue, tableRegID=tableRegID, groupID=groupID, label=(((label + ' [') + str(keyIDValue)) + ']'), englishText=englishText, descriptionText=None, wordTypeID=wordTypeID)
                    syncResult[mappingResult] += 1

                mappingsForResource = localization.KeyToMessageMapping.GetMappingsForRegisteredResource(tableRegID)
                if (len(updatedMappedEntries) < len(mappingsForResource)):
                    for aMappingEntry in mappingsForResource:
                        keyIDValue = aMappingEntry.keyID
                        if (keyIDValue not in updatedMappedEntries):
                            messageEntry = localization.Message.GetMessageByID(aMappingEntry.messageID)
                            if ((messageEntry is not None) and (messageEntry.groupID != aRow.groupID)):
                                groupEntry = groupTable.GetRowByKey(keyId1=messageEntry.groupID)
                                if groupEntry.isReadOnly:
                                    possibleOrphanedGroups.add(groupEntry.groupID)
                            aMappingEntry.Delete()
                            syncResult[localization.KeyToMessageMapping.DELETED_ENTRY] += 1

                i = 0
                while (i < self.MAX_GROUP_DEPTH):
                    possibleOrphanedGroups = self._DeleteOrphanedGroupsFrom(possibleOrphanedGroups, messagesTable, groupTable)
                    if (len(possibleOrphanedGroups) == 0):
                        break
                    else:
                        if (len(possibleOrphanedGroups) == 1):
                            if (aRow.groupID in possibleOrphanedGroups):
                                break
                    i = (i + 1)


        return updatedEntriesPerTable



    def _ReadLocalizationPickle(self):
        self.languagesDefined = {}
        self.languageLabels = {}
        self.languageTexts = {}
        self.languageMetaData = {}
        self.languageTypesWithProperties = {}
        self.tableRegistration = {}
        self.messageMapping = {}
        pickleFile = miscUtil.GetCommonResource(((self.COMMON_RESOURCE_PATH + self.PICKLE_MAIN_NAME) + self.PICKLE_EXT))
        if not pickleFile:
            LogError(('pickleFile is None. Name = %s' % (self.PICKLE_MAIN_NAME + self.PICKLE_EXT)))
            return False
        else:
            pickledData = pickleFile.Read()
            if not pickledData:
                LogError(('pickledData is None. File name = %s' % (self.PICKLE_MAIN_NAME + self.PICKLE_EXT)))
                return False
            unPickledObject = pickle.loads(pickledData)
            if (unPickledObject and (self.FIELD_LABELS in unPickledObject)):
                labelsDict = unPickledObject[self.FIELD_LABELS]
                for aMessageID in labelsDict:
                    dataRow = labelsDict[aMessageID]
                    pathAndLabelKey = None
                    if dataRow[self.COLUMN_FULLPATH]:
                        aFullPath = dataRow[self.COLUMN_FULLPATH]
                        pathAndLabelKey = ((aFullPath + '/') + dataRow[self.COLUMN_LABEL])
                    else:
                        pathAndLabelKey = dataRow[self.COLUMN_LABEL]
                    self.languageLabels[pathAndLabelKey] = dataRow
                    labelsDict[aMessageID] = None

            else:
                LogError(("didn't find 'labels' in the unpickled object. File name = %s" % (self.PICKLE_MAIN_NAME + self.PICKLE_EXT)))
                return False
            if (self.FIELD_LANGUAGES in unPickledObject):
                self.languagesDefined = unPickledObject[self.FIELD_LANGUAGES]
            else:
                LogError(("didn't find 'languages' in the unpickled object. File name = %s" % (self.PICKLE_MAIN_NAME + self.PICKLE_EXT)))
                return False
            if ((self.FIELD_REGISTRATION in unPickledObject) and (self.FIELD_MAPPING in unPickledObject)):
                self.tableRegistration = unPickledObject[self.FIELD_REGISTRATION]
                self.messageMapping = unPickledObject[self.FIELD_MAPPING]
            else:
                LogError(("didn't find 'mapping' or 'registration' in the unpickled object. File name = %s" % (self.PICKLE_MAIN_NAME + self.PICKLE_EXT)))
                return False
            if (self.FIELD_TYPES in unPickledObject):
                self.languageTypesWithProperties = unPickledObject[self.FIELD_TYPES]
            else:
                LogError(("didn't find 'types' in the unpickled object. File name = %s" % (self.PICKLE_MAIN_NAME + self.PICKLE_EXT)))
                return False
            pickleFile.Close()
            pickleFile = None
            for aLangCode in self.languagesDefined:
                pickleFile = miscUtil.GetCommonResource((((self.COMMON_RESOURCE_PATH + self.PICKLE_PREFIX) + aLangCode) + self.PICKLE_EXT))
                if not pickleFile:
                    LogError(('pickle file is None. Name = %s' % ((self.PICKLE_PREFIX + aLangCode) + self.PICKLE_EXT)))
                    return False
                pickledData = pickleFile.Read()
                if not pickledData:
                    LogError(('pickled data is None. File name = %s' % ((self.PICKLE_PREFIX + aLangCode) + self.PICKLE_EXT)))
                    return False
                unPickledObject = pickle.loads(pickledData)
                if (unPickledObject and (len(unPickledObject) == self.LANGUAGE_NUMBER_OF_FIELDS)):
                    self.languageTexts[aLangCode] = unPickledObject[self.LANGUAGE_FIELD_TEXTS]
                    self.languageMetaData[aLangCode] = unPickledObject[self.LANGUAGE_FIELD_DATA]
                else:
                    LogError(("didn't find required parts in unpickled object. File name = %s" % ((self.PICKLE_PREFIX + aLangCode) + self.PICKLE_EXT)))
                    return False
                pickleFile.Close()
                pickleFile = None

            return True



    def _GetByID(self, messageID, languageID, **kwargs):
        try:
            text = self.languageTexts[languageID][messageID]
        except KeyError, e:
            LogError(('a non existent messageID was requested. messageID,languageID : %s,%s' % (messageID, languageID)))
            return 
        return localization._Parse(text, messageID, languageID, **kwargs)



    def _GetAllMetaDataPerLanguage(self, messageID, languageID):
        properties = self.languageMetaData.get(languageID, {}).get(messageID, None)
        if (properties is not None):
            properties = properties.copy()
        return properties



    def _GetMetaData(self, messageID, propertyName, languageID):
        return self.languageMetaData.get(languageID, {}).get(messageID, {}).get(propertyName, None)



    def _GetLanguageFromSession(self):
        try:
            return localization.ISO639_TO_LOCALECODE[session.languageID]
        except (KeyError, AttributeError), e:
            return localization.ISO_CODE_ENGLISH



    def _MakeRowDicts(self, rowList, columnNames, tableUniqueKey = None):
        tableData = {}
        rowCount = 0
        for aRow in rowList:
            rowData = {}
            rowKeyValue = False
            if tableUniqueKey:
                rowKeyValue = getattr(aRow, tableUniqueKey)
            for aColumn in columnNames:
                columnData = getattr(aRow, aColumn)
                rowData[aColumn] = columnData

            if (tableUniqueKey and rowKeyValue):
                tableData[rowKeyValue] = rowData
            else:
                tableData[rowCount] = rowData
            rowCount = (rowCount + 1)

        return tableData



    def _GetTableRowsFromProcedure(self, functionCall, columnNames = None, uniqueKey = None):
        resultSet = functionCall()
        if (columnNames is None):
            columnNames = resultSet.columns
        return self._MakeRowDicts(resultSet, columnNames, uniqueKey)



    def _GetTableRows(self, schemaAndTableName, columnNames = None, tableUniqueKey = None):
        bsdTableService = sm.GetService('bsdTable')
        aBsdTable = bsdTableService.GetTable(schemaAndTableName)
        allRows = aBsdTable.GetRows()
        if (columnNames is None):
            columnNames = aBsdTable.GetDataColumnNames()
        return self._MakeRowDicts(allRows, columnNames, tableUniqueKey)



    def _SetHardcodedStringDetection(self):
        if (boot.role == 'client'):
            while not hasattr(__builtin__, 'prefs'):
                blue.synchro.Yield()

            localizationUtil.SetHardcodedStringDetection(getattr(prefs, 'showHardcodedStrings', False))



    def _ResolveDynamicPath(self, groupPathString, staticGroupID, wordTypeID):
        folderNames = groupPathString.split(localization.FOLDER_NAME_CHAR_SEPARATOR)
        currentParentID = staticGroupID
        newGroup = None
        messageGroups = sm.GetService('bsdTable').GetTable('zlocalization.messageGroups')
        for currentGroupName in folderNames:
            if (newGroup is None):
                groupRows = messageGroups.GetRows(parentID=currentParentID, groupName=currentGroupName)
                groupRow = (groupRows[0] if (len(groupRows) > 0) else None)
            if (groupRow is not None):
                currentParentID = groupRow.groupID
            else:
                newGroup = localization.MessageGroup.Create(parentID=currentParentID, groupName=currentGroupName, isReadOnly=1, wordTypeID=wordTypeID)
            currentParentID = newGroup.groupID

        if (newGroup is None):
            return (groupRow.groupID, False)
        else:
            return (newGroup.groupID, True)



    def _DeleteOrphanedGroupsFrom(self, setOfDynamicGroups, messagesTable, groupTable):
        setOfParentGroups = set()
        for aGroupID in setOfDynamicGroups:
            messagesInGroup = messagesTable.GetRows(groupID=aGroupID)
            subGroups = groupTable.GetRows(parentID=aGroupID)
            if ((len(messagesInGroup) == 0) and (len(subGroups) == 0)):
                groupRow = groupTable.GetRowByKey(keyId1=aGroupID)
                setOfParentGroups.add(groupRow.parentID)
                groupRow.Delete()

        return setOfParentGroups



    def _UndoXMLSafeTagName(self, originalName):
        return originalName.replace('_', ' ')



    def _GetXMLSafeTagName(self, originalName):
        return originalName.replace(' ', '_')



    def _ExportXMLElementsFromDatabase(self):
        db2service = sm.GetService('DB2')
        if not db2service:
            LogError(('didnt get the DB2 service. db2service = %s' % db2service))
            return 
        else:
            textDataElement = xml.etree.ElementTree.Element(tag=localization.EXPORT_XML_TEXT_ROOT)
            messagesExported = 0
            metaDataExported = 0
            dataForXMLResultSet = db2service.zlocalization.GetTextDataForXMLExport(1)
            englishTextsResultSet = dataForXMLResultSet[0]
            allPropertiesResultSet = dataForXMLResultSet[1]
            allMetaDataResultSet = dataForXMLResultSet[2]
            requestedLanguagesResultSet = dataForXMLResultSet[3]
            translationsResultSet = dataForXMLResultSet[4]
            languageCodesResultSet = db2service.zlocalization.LanguageCodes_SelectEnabled()
            languageCodesDict = self._MakeRowDicts(languageCodesResultSet, languageCodesResultSet.columns, self.COLUMN_LANGUAGEID)
            messageAndPropertyToMetaDataIndex = {}
            messageToTranslatedIndex = {}
            typeAndLanguageToPropertiesIndex = {}
            for aTranslatedEntry in translationsResultSet:
                messageToTranslatedIndex[(aTranslatedEntry.messageID, languageCodesDict[aTranslatedEntry.languageID][self.COLUMN_LANGUAGE_CODE_STRING])] = aTranslatedEntry

            for allMetaData in allMetaDataResultSet:
                languageCodeString = languageCodesDict[allMetaData.languageID][self.COLUMN_LANGUAGE_CODE_STRING]
                messageAndPropertyToMetaDataIndex[(allMetaData.messageID,
                 languageCodeString,
                 allMetaData.propertyName)] = allMetaData

            for aProperty in allPropertiesResultSet:
                aPropertyList = typeAndLanguageToPropertiesIndex.get((aProperty.wordTypeID, aProperty.languageCodeString), None)
                if (aPropertyList is None):
                    aPropertyList = typeAndLanguageToPropertiesIndex[(aProperty.wordTypeID, aProperty.languageCodeString)] = []
                aPropertyList.append(aProperty)

            for aTextRow in englishTextsResultSet:
                attributes = {localization.EXPORT_XML_MESSAGEID: str(aTextRow.messageID),
                 localization.EXPORT_XML_DATAID: str(aTextRow.dataID),
                 localization.EXPORT_XML_PATH: aTextRow.FullPath}
                messageElement = xml.etree.ElementTree.Element(localization.EXPORT_XML_MESSAGE, attrib=attributes)
                textDataElement.append(messageElement)
                messagesExported += 1
                englishTextElement = self._MakeXMLLanguageTextElements(messageElement, aTextRow, localization.ISO_CODE_ENGLISH, {})
                descriptionElement = xml.etree.ElementTree.Element(localization.EXPORT_XML_DESCRIPTION)
                descriptionElement.text = aTextRow.context
                messageElement.append(descriptionElement)
                englishMetaElement = self._MakeXMLLanguageMetaDataElements(englishTextElement, aTextRow, localization.ISO_CODE_ENGLISH, typeAndLanguageToPropertiesIndex, messageAndPropertyToMetaDataIndex)
                if (englishMetaElement is not None):
                    metaDataExported += 1
                translationsElement = xml.etree.ElementTree.Element(tag=localization.EXPORT_XML_TRANSLATIONS)
                messageElement.append(translationsElement)
                for aLanguageEntry in requestedLanguagesResultSet:
                    if (aLanguageEntry.languageCodeString != localization.ISO_CODE_ENGLISH):
                        languageTextElement = self._MakeXMLLanguageTextElements(translationsElement, aTextRow, aLanguageEntry.languageCodeString, messageToTranslatedIndex)
                        if (aTextRow.wordTypeID is not None):
                            if (aLanguageEntry.languageCodeString != localization.ISO_CODE_ENGLISH):
                                languageMetaElement = self._MakeXMLLanguageMetaDataElements(languageTextElement, aTextRow, aLanguageEntry.languageCodeString, typeAndLanguageToPropertiesIndex, messageAndPropertyToMetaDataIndex)
                                if (languageMetaElement is not None):
                                    metaDataExported += 1


            LogInfo(("Export method exported '%i' message(s) and '%i' metaData entries (including english metadata) " % (messagesExported, metaDataExported)))
            return textDataElement



    def _MakeXMLLanguageTextElements(self, parentElement, aTextRow, languageCodeString, messageToTranslatedIndex):
        languageTextElement = xml.etree.ElementTree.Element(self._GetXMLSafeTagName(languageCodeString))
        parentElement.append(languageTextElement)
        if (languageCodeString == localization.ISO_CODE_ENGLISH):
            attributes = {}
        else:
            attributes = {localization.EXPORT_XML_STATUS: localization.EXPORT_XML_TRANSLATE}
        languageTextEntryElement = xml.etree.ElementTree.Element(localization.EXPORT_XML_TEXT, attrib=attributes)
        languageTextElement.append(languageTextEntryElement)
        aTranslatedEntry = messageToTranslatedIndex.get((aTextRow.messageID, languageCodeString), None)
        if aTranslatedEntry:
            languageTextEntryElement.text = aTranslatedEntry.text
        else:
            languageTextEntryElement.text = aTextRow.text
        return languageTextElement



    def _MakeXMLLanguageMetaDataElements(self, parentElement, aTextRow, languageCodeString, typeAndLanguageToPropertiesIndex, messageAndPropertyToMetaDataIndex):
        languageMetaElement = None
        aProperties = typeAndLanguageToPropertiesIndex.get((aTextRow.wordTypeID, languageCodeString))
        if aProperties:
            languageMetaElement = xml.etree.ElementTree.Element(localization.EXPORT_XML_METADATA)
            parentElement.append(languageMetaElement)
            for aProperty in aProperties:
                if (languageCodeString == localization.ISO_CODE_ENGLISH):
                    attributes = {}
                else:
                    attributes = {localization.EXPORT_XML_STATUS: localization.EXPORT_XML_TRANSLATE}
                languageProperty = xml.etree.ElementTree.Element(self._GetXMLSafeTagName(aProperty.propertyName), attrib=attributes)
                languageMetaElement.append(languageProperty)
                languageMetaDataRow = messageAndPropertyToMetaDataIndex.get((aTextRow.messageID,
                 languageCodeString,
                 aProperty.propertyName), None)
                if (languageMetaDataRow is not None):
                    languageProperty.text = languageMetaDataRow.metaDataValue

        return languageMetaElement



    def _ImportXMLIntoDatabase(self, textRootElement):
        db2service = sm.GetService('DB2')
        if not db2service:
            LogError(('didnt get the DB2 service. db2service = %s' % db2service))
            return (None, None)
        else:
            self.ADDED = 'Added text'
            self.UPDATED = 'Updated text'
            self.UNCHANGED = 'Unchanged text'
            self.SKIPPED = 'Skipped messageID'
            self.EMPTY_TAG = 'Empty tags'
            updatedTextEntries = {self.ADDED: 0,
             self.UPDATED: 0,
             self.UNCHANGED: 0,
             self.SKIPPED: 0,
             self.EMPTY_TAG: 0}
            updatedMetaDataEntries = {self.ADDED: 0,
             self.UPDATED: 0,
             self.UNCHANGED: 0,
             self.EMPTY_TAG: 0}
            messageTextsTable = sm.GetService('bsdTable').GetTable(localization.MESSAGE_TEXTS_TABLE)
            metaDataTable = sm.GetService('bsdTable').GetTable(localization.WORD_METADATA_TABLE)
            messagesTable = sm.GetService('bsdTable').GetTable(localization.MESSAGES_TABLE)
            languageCodesResultSet = db2service.zlocalization.LanguageCodes_SelectEnabled()
            languageCodesDict = self._MakeRowDicts(languageCodesResultSet, languageCodesResultSet.columns, self.COLUMN_LANGUAGE_CODE_STRING)
            allPropertiesResultSet = db2service.zlocalization.WordTypes_GetAllProperties()
            propertyAndLanguageToPropertiesIndex = {}
            for aProperty in allPropertiesResultSet:
                propertyAndLanguageToPropertiesIndex[(aProperty.propertyName, aProperty.languageCodeString)] = aProperty

            if (textRootElement is not None):
                allMessageElements = textRootElement.findall(localization.EXPORT_XML_MESSAGE)
                for aMessageElement in allMessageElements:
                    dataID = int(aMessageElement.get(localization.EXPORT_XML_DATAID))
                    messageID = int(aMessageElement.get(localization.EXPORT_XML_MESSAGEID))
                    messageRows = messagesTable.GetRowByKey(messageID)
                    if not messageRows:
                        LogError(("Import didnt find a matching messageID in DB; skipping importing this entry : '%s'" % messageID))
                        updatedTextEntries[self.SKIPPED] += 1
                        continue
                    translationElement = aMessageElement.find(localization.EXPORT_XML_TRANSLATIONS)
                    languageElements = list(translationElement)
                    for aLanguageElement in languageElements:
                        languageTextElement = aLanguageElement.find(localization.EXPORT_XML_TEXT)
                        languageCodeString = self._UndoXMLSafeTagName(aLanguageElement.tag)
                        languageID = languageCodesDict[languageCodeString][self.COLUMN_LANGUAGEID]
                        translatedText = languageTextElement.text
                        if translatedText:
                            updateStatus = self._ImportTextEntry(messageID, translatedText, languageID, messageTextsTable)
                            updatedTextEntries[updateStatus] += 1
                        else:
                            updatedTextEntries[self.EMPTY_TAG] += 1
                        metaDataElement = aLanguageElement.find(localization.EXPORT_XML_METADATA)
                        if (metaDataElement is not None):
                            languageMetaDataElements = list(metaDataElement)
                            for aPropertyElement in languageMetaDataElements:
                                propertyName = self._UndoXMLSafeTagName(aPropertyElement.tag)
                                metaDataText = aPropertyElement.text
                                if metaDataText:
                                    try:
                                        aPropertyEntry = propertyAndLanguageToPropertiesIndex[(propertyName, languageCodeString)]
                                        wordPropertyID = aPropertyEntry.wordPropertyID
                                        updateStatus = self._ImportMetaDataEntry(messageID, wordPropertyID, metaDataText, metaDataTable)
                                        updatedMetaDataEntries[updateStatus] += 1
                                    except IndexError, e:
                                        LogError(("Import didnt find a matching property in DB; skipping importing this property (messageID,property) : '%s,%s'" % (messageID, propertyName)))
                                else:
                                    updatedMetaDataEntries[self.EMPTY_TAG] += 1



            return (updatedTextEntries, updatedMetaDataEntries)



    def _ImportMetaDataEntry(self, messageID, wordPropertyID, metaDataText, metaDataTable):
        updateStatus = self.UNCHANGED
        metaDataEntries = metaDataTable.GetRows(messageID=messageID, wordPropertyID=wordPropertyID)
        if (metaDataEntries and len(metaDataEntries)):
            if (metaDataEntries[0].metaDataValue != metaDataText):
                metaDataEntries[0].metaDataValue = metaDataText
                updateStatus = self.UPDATED
            else:
                updateStatus = self.UNCHANGED
        else:
            metaDataTable.AddRow(metaDataValue=metaDataText, messageID=messageID, wordPropertyID=wordPropertyID)
            updateStatus = self.ADDED
        return updateStatus



    def _ImportTextEntry(self, messageID, translatedText, languageID, messageTextsTable):
        updateStatus = self.UNCHANGED
        try:
            englishText = localization.MessageText.GetMessageTextsByMessageID(messageID, languageID=localization.ISO_ID_ENGLISH)[0]
        except (TypeError, IndexError), e:
            LogError(("Import didnt find a matching english text in DB; skipping importing this entry. messageID : '%s'" % messageID))
            return updateStatus
        existingTranslation = localization.MessageText.GetMessageTextsByMessageID(messageID, languageID=languageID)
        if (existingTranslation and len(existingTranslation)):
            if ((existingTranslation[0].text != translatedText) and (englishText.text != translatedText)):
                existingTranslation[0].text = translatedText
                updateStatus = self.UPDATED
            else:
                updateStatus = self.UNCHANGED
        elif (englishText.text != translatedText):
            messageTextsTable.AddRow(messageID, languageID, text=translatedText)
            updateStatus = self.ADDED
        else:
            updateStatus = self.EMPTY_TAG
        return updateStatus



LOCALIZATION_REF = None
if (boot.appname == 'WOD'):
    LOCALIZATION_REF = Localization()
elif ((boot.appname == 'EVE') and (hasattr(prefs, 'enableCerberusLocalizationModule') and (prefs.enableCerberusLocalizationModule == 1))):
    LOCALIZATION_REF = Localization()
if (LOCALIZATION_REF is not None):
    exports = {'localization.ChangeLocale': LOCALIZATION_REF.ChangeLocale,
     'localization.WriteLocalizationPickle': LOCALIZATION_REF.WriteLocalizationPickle,
     'localization.GetByID': LOCALIZATION_REF.GetByID,
     'localization.GetByLabel': LOCALIZATION_REF.GetByLabel,
     'localization.GetPlaceholderLabel': LOCALIZATION_REF.GetPlaceholderLabel,
     'localization.GetByMapping': LOCALIZATION_REF.GetByMapping,
     'localization.GetMetaData': LOCALIZATION_REF.GetMetaData,
     'localization.GetAllMetaDataPerLanguage': LOCALIZATION_REF.GetAllMetaDataPerLanguage,
     'localization.GetAllMetaData': LOCALIZATION_REF.GetAllMetaData,
     'localization.IsValidTypeAndProperty': LOCALIZATION_REF.IsValidTypeAndProperty,
     'localization.GetResourceFilePaths': LOCALIZATION_REF.GetResourceFilePaths,
     'localization.SyncDataFromRegisteredTables': LOCALIZATION_REF.SyncDataFromRegisteredTables,
     'localization.ExportXMLFromDatabase': LOCALIZATION_REF.ExportXMLFromDatabase,
     'localization.ExportToXMLFileFromDatabase': LOCALIZATION_REF.ExportToXMLFileFromDatabase,
     'localization.ImportXMLIntoDatabase': LOCALIZATION_REF.ImportXMLIntoDatabase,
     'localization.ImportFromXMLFileIntoDatabase': LOCALIZATION_REF.ImportFromXMLFileIntoDatabase,
     'localization.LogInfo': LogInfo,
     'localization.LogWarn': LogWarn,
     'localization.LogError': LogError,
     'localization._ReadLocalizationPickle': LOCALIZATION_REF._ReadLocalizationPickle}

